/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: DOMTest.java,v $
 *
 */

package com.cidero.upnp;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;


/**
 *
 *  XML parser test
 *  
 */
public class DOMTest
{
  public DOMTest()
  {
  }

  public void performDemo( String uri ) {

    System.out.println("Parsing XML file: " + uri + "\n" );

    DOMParser parser = new DOMParser();
    
    String xmlStr = "<?xml version=\"1.0\" encoding=\"UTF8\" ?><DIDL-Lite xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp\"><item id=\"10\" parentID=\"1\" restricted=\"false\" > <upnp:class>object.item.videoItem.movie</upnp:class> <dc:title>Terminator</dc:title> <upnp:genre>Action</upnp:genre> <upnp:rating>Action</upnp:rating> <upnp:actor>Arnold</upnp:actor> <upnp:director>Arnold</upnp:director> <dc:description>Machines rule the future</dc:description></item></DIDL-Lite> \0 ";

    byte[] xmlByteArray = xmlStr.getBytes();
    ByteArrayInputStream xmlStream = new  ByteArrayInputStream( xmlByteArray );
    //    InputStreamReader xmlReader = new InputStreamReader( xmlStream );

    try 
    {
      parser.parse( new InputSource( xmlStream ) );
      
      //parser.parse( uri );

      Document doc = parser.getDocument();

      printNode( doc, "" );

      System.out.println("\nDone parsing\n");
      
      
      System.out.println("Converting DOM to CDS\n");

      DOMToCDS( doc );

    }
    catch( IOException e ) 
    {
      System.out.println("Error reading URI: " + e.getMessage() );
      
    }
    catch( SAXException e ) 
    {
      System.out.println("Error parsing URI: " + e.getMessage() );
      
    }

  }


  public void printNode( Node node, String indent )
  {
    // Determine type of node

    switch( node.getNodeType() )
    {
      case Node.DOCUMENT_NODE:
        System.out.println("<xml version = \"1.0\">\n");
        Document doc = (Document)node;
        printNode( doc.getDocumentElement(), "" );
        break;

      case Node.ELEMENT_NODE:
        String name = node.getNodeName();
        System.out.print( indent + "<" + name );

        NamedNodeMap attributes = node.getAttributes();
        for( int n = 0 ; n < attributes.getLength() ; n++ )
        {
          Node current = attributes.item(n);
          System.out.print( " " + current.getNodeName() +
                            "=\"" + current.getNodeValue() +
                            "\"" );
        }
        
        NodeList children = node.getChildNodes();

        // If simple node, don't bother with newline between tags
        if( (children != null) && (children.getLength() > 0) &&
            (attributes.getLength() > 0 ) )
        {
          System.out.println( ">" );
        }
        else
        {
          System.out.print( ">" );
        }
        

        // Recurse on children

        if( children != null )
        {
          for( int n = 0 ; n < children.getLength() ; n++ )
          {
            printNode( children.item(n), indent + "  " );
          }
        }
        
        if( (children != null) && (children.getLength() > 0) &&
            (attributes.getLength() > 0 ) )
        {
          System.out.print( indent + "</" + name + ">" );
        }
        else
        {
          System.out.print( "</" + name + ">" );
        }

        break;
        
      case Node.TEXT_NODE:
      case Node.CDATA_SECTION_NODE:

        System.out.print( node.getNodeValue() );
        break;

      case Node.PROCESSING_INSTRUCTION_NODE:
        
        break;

      case Node.ENTITY_REFERENCE_NODE:
        
        break;

      case Node.DOCUMENT_TYPE_NODE:
        
        break;


    }

  }
  
  public void DOMToCDS( Node node )
  {

    switch( node.getNodeType() )
    {

      case Node.DOCUMENT_NODE:
        System.out.println("<xml version = \"1.0\">\n");
        Document doc = (Document)node;
        DOMToCDS( doc.getDocumentElement() );
        break;

      case Node.ELEMENT_NODE:

        //
        // This is the DIDL-Lite node - Process all children containers and/or
        // items (non recursively)
        //
        System.out.println("Element node: " + node.getNodeName() );
        DOMContainersAndItemsToCDS( node.getChildNodes() );
        break;


    }
  }
  
  public void DOMContainersAndItemsToCDS( NodeList nodeList )
  {
    
    System.out.println("N child nodes: " + nodeList.getLength() );

    for( int n = 0 ; n < nodeList.getLength() ; n++ )
    {
      Node node = nodeList.item(n);
      
      System.out.println("child node: " + node.getNodeName() +
                         "value: [" + node.getNodeValue() + "]" );


      // Skip over non-element nodes
      if( node.getNodeType() != Node.ELEMENT_NODE )
      {
        System.out.println("Not an element - skipping\n");
        continue;
      }
      
      
      Element element = (Element)node;
      
      NodeList classElementList = element.getElementsByTagName( "upnp:class" );

      if( classElementList.getLength() != 1 )
      {
        System.out.println("Error - element has no upnp class tag\n");
        continue;
      }
      
      System.out.println("Found matching upnp:class element\n");

      // Should be single text sub-node containing class name

      NodeList textNodeList = classElementList.item(0).getChildNodes();
      
      if( textNodeList.getLength() != 1 )
      {
        System.out.println("Error - upnp class element childNodes != 1\n");
        continue;
      }

      try
      {
        String upnpClass = textNodeList.item(0).getNodeValue();

        // Instantiate object of the appropriate type and initialize it
        // with all the data in the DOM version of the UPNP container/item 

        System.out.println("upnpClass is: " + upnpClass );

        CDSObject obj = CreateCDSObject( upnpClass,
                                                               node );

      }
      catch( DOMException e )
      {
        System.out.println("UPNP class not found" + e.getMessage() );
      }

    }

  }
  
  public CDSObject CreateCDSObject( String upnpClass,
                                                          Node node )
  {
    System.out.println("UPNP class '" + upnpClass + "'  back to XML" );

    CDSFilter filter = new CDSFilter("*");

    if( upnpClass.equals( "object.item.videoItem.movie" ) )
    {
      //
      // Call form of constructor that takes a DOM node
      // DOM node gets passed down constructor chain all the way to
      // the base class.
      //
      CDSMovie movie = new CDSMovie( node );
      System.out.println( movie.toXML( filter ) );
      return movie;

    }
    else if( upnpClass.equals( "object.item.videoItem" ) )
    {
      CDSVideoItem videoItem = new CDSVideoItem( node );
      System.out.println( videoItem.toXML( filter ) );
      return videoItem;
    }
    else if( upnpClass.equals( "object.item.imageItem.photo" ) )
    {
      CDSPhoto photo = new CDSPhoto( node );
      System.out.println( photo.toXML( filter ) );
      return photo;
    }
    else if( upnpClass.equals( "object.item.imageItem" ) )
    {
      CDSImageItem imageItem = new CDSImageItem( node );
      System.out.println( imageItem.toXML( filter ) );
      return imageItem;
    }
    else if( upnpClass.equals( "object.item.audioItem.musicTrack" ) )
    {
      CDSMusicTrack musicTrack =
        new CDSMusicTrack( node );
      System.out.println( musicTrack.toXML( filter ) );
      return musicTrack;
    }
    else if( upnpClass.equals( "object.item.audioItem" ) )
    {
      CDSAudioItem audioItem =
        new CDSAudioItem( node );
      System.out.println( audioItem.toXML( filter ) );
      return audioItem;
    }
    else if( upnpClass.equals( "object.item" ) )
    {
      CDSItem item = new CDSItem( node );
      System.out.println( item.toXML( filter ) );
      return item;
    }
    else if( upnpClass.equals( "object.container.musicAlbum" ) )
    {
      CDSMusicAlbum obj = 
        new CDSMusicAlbum( node );
      System.out.println( obj.toXML( filter ) );
      return obj;
    }
    else if( upnpClass.equals( "object.container.storageFolder" ) )
    {
      CDSStorageFolder obj = 
        new CDSStorageFolder( node );
      System.out.println( obj.toXML( filter ) );
      return obj;
    }
    else if( upnpClass.equals( "object.container" ) )
    {
      CDSContainer obj = 
        new CDSContainer( node );
      System.out.println( obj.toXML( filter ) );
      return obj;
    }
    else
    {
      System.out.println("Unsupported UPNP object type '" + upnpClass + "'" );
    }

    return null;
    
  }


  public static void main( String[] args )
  {
    if( args.length != 1 )
    {
      System.out.println("Usage: java DOMTest <XML file>" );
      System.exit(0);
    }
    
    String uri = args[0];
    
    DOMTest domTest = new DOMTest();

    domTest.performDemo( uri );
    
  }


}
